package fr.cdesire.sudoku.core;

import java.util.HashSet;
import java.util.Set;

import com.google.common.collect.Sets;

import fr.cdesire.sudoku.core.commons.Grille;
import fr.cdesire.sudoku.core.commons.Position;
import fr.cdesire.sudoku.core.enums.Valeur;
import fr.cdesire.sudoku.core.exceptions.GrilleIncompleteException;
import fr.cdesire.sudoku.core.exceptions.GrilleInvalideException;
import fr.cdesire.sudoku.core.exceptions.SudokuCoreException;

/**
 * Validation de grilles Sudoku.
 * 
 * @author cedric.desire@gmail.com
 */
public class Validation {

    /**
     * Constructeur privé.
     */
    private Validation() {
        super();
    }

    /**
     * Vérification que la règle Sudoku est respectée : une et une seule
     * même valeur par ligne, une et une seule même valeur par colonne,
     * une et une seule même valeur par région.
     *
     * @param grille Grille à valider.
     * @throws SudokuCoreException Lève une GrilleInvalideException si la
     * grille n'est pas valide.
     */
    protected static void valider(Grille grille) throws SudokuCoreException {

        Set<Position> positionsRenseignees = grille.getValeursRenseignees().keySet();

        for (Position positionRenseignee : positionsRenseignees) {

            Valeur valeurRenseignee = grille.getValeursRenseignees().get(positionRenseignee);

            Set<Position> positionsImpactees = grille.getFormatGrille().getPositionsDependantes().get(positionRenseignee);
            Set<Position> positionsImpacteesExistantes = Sets.intersection(positionsRenseignees, positionsImpactees);

            for (Position positionImpacteeExistante : positionsImpacteesExistantes) {
                Valeur valeurImpacteeExistante = grille.getValeursRenseignees().get(positionImpacteeExistante);
                if (valeurRenseignee.equals(valeurImpacteeExistante)) {
                    throw new GrilleInvalideException(positionRenseignee, positionImpacteeExistante);
                }
            }
        }
    }

    /**
     * Vérifie que le nombre de valeurs saisies est suffisant pour permettre
     * la résolution de la grille.
     *
     * @param grille Grille à vérifier
     * @throws SudokuCoreException Lève une  GrilleIncompleteException si le
     * nombre de valeurs saisies est insuffisant.
     */
    protected static void verifierGrilleComplete(Grille grille) throws SudokuCoreException {

        Set<Position> positionsRenseignees = grille.getValeursRenseignees().keySet();

        Set<Position> zoneCouverte = new HashSet<Position>();

        for (Position positionRenseignee : positionsRenseignees) {
            zoneCouverte.addAll(grille.getFormatGrille().getPositionsDependantes().get(positionRenseignee));
        }

        if (zoneCouverte.size() != grille.getFormatGrille().getNbCases()) {
            throw new GrilleIncompleteException();
        }
    }
}
